using System;
using System.Data;
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;
using SeataNet.Core.Common;
using Microsoft.Extensions.Logging;

namespace SeataNet.Core.XA
{
    /// <summary>
    /// XA连接代理类，实现XA协议的两阶段提交
    /// </summary>
    public class XaConnection : DbConnection, IDisposable
    {
        private readonly DbConnection _innerConnection;
        private readonly string _xid;
        private readonly ILogger<XaConnection> _logger;
        private XaTransaction _xaTransaction;
        private bool _disposed = false;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="innerConnection">内部数据库连接</param>
        /// <param name="xid">全局事务ID</param>
        /// <param name="logger">日志记录器</param>
        public XaConnection(DbConnection innerConnection, string xid, ILogger<XaConnection>? logger = null)
        {
            _innerConnection = innerConnection ?? throw new ArgumentNullException(nameof(innerConnection));
            _xid = xid ?? throw new ArgumentNullException(nameof(xid));
            _logger = logger ?? Microsoft.Extensions.Logging.Abstractions.NullLogger<XaConnection>.Instance;

            // 创建XA事务 (use null for logger since we can't convert ILogger<XaConnection> to ILogger<XaTransaction>)
            _xaTransaction = new XaTransaction(_innerConnection, xid, null);
        }

        /// <summary>
        /// 分支ID
        /// </summary>
        public long BranchId { get; set; }

        /// <summary>
        /// 全局事务ID
        /// </summary>
        public string Xid => _xid;

        /// <summary>
        /// 内部连接
        /// </summary>
        public DbConnection InnerConnection => _innerConnection;

        /// <summary>
        /// 数据库连接字符串
        /// </summary>
        public override string? ConnectionString
        {
            get => _innerConnection.ConnectionString;
            set => _innerConnection.ConnectionString = value ?? throw new ArgumentNullException(nameof(value));
        }

        /// <summary>
        /// 连接超时时间
        /// </summary>
        public override int ConnectionTimeout => _innerConnection.ConnectionTimeout;

        /// <summary>
        /// 数据库名称
        /// </summary>
        public override string Database => _innerConnection.Database;

        /// <summary>
        /// 数据源
        /// </summary>
        public override string DataSource => _innerConnection.DataSource;

        /// <summary>
        /// 服务器版本
        /// </summary>
        public override string ServerVersion => _innerConnection.ServerVersion;

        /// <summary>
        /// 连接状态
        /// </summary>
        public override ConnectionState State => _innerConnection.State;

        /// <summary>
        /// 开始事务
        /// </summary>
        /// <param name="isolationLevel">隔离级别</param>
        /// <returns>事务对象</returns>
        protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
        {
            _logger.LogInformation("开始XA事务: xid={xid}, isolationLevel={isolationLevel}", _xid, isolationLevel);

            // 使用XA事务
            // Note: IsolationLevel is readonly, set by inner transaction in constructor
            return _xaTransaction;
        }

        /// <summary>
        /// 更改数据库
        /// </summary>
        /// <param name="databaseName">数据库名称</param>
        public override void ChangeDatabase(string databaseName)
        {
            _innerConnection.ChangeDatabase(databaseName);
        }

        /// <summary>
        /// 关闭连接
        /// </summary>
        public override void Close()
        {
            _innerConnection.Close();
        }

        /// <summary>
        /// 创建命令
        /// </summary>
        /// <returns>命令对象</returns>
        protected override DbCommand CreateDbCommand()
        {
            var command = _innerConnection.CreateCommand();
            
            // 如果当前有XA事务，设置事务
            if (_xaTransaction != null)
            {
                command.Transaction = _xaTransaction.InnerTransaction;
            }
            
            return command;
        }

        /// <summary>
        /// 打开连接
        /// </summary>
        public override void Open()
        {
            _logger.LogInformation("打开XA连接: xid={xid}", _xid);
            _innerConnection.Open();
        }

        /// <summary>
        /// 异步打开连接
        /// </summary>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>任务</returns>
        public override async Task OpenAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("异步打开XA连接: xid={xid}", _xid);
            await _innerConnection.OpenAsync(cancellationToken);
        }

        /// <summary>
        /// 提交XA事务
        /// </summary>
        /// <returns>任务</returns>
        public async Task CommitAsync()
        {
            if (_xaTransaction != null)
            {
                _logger.LogInformation("提交XA事务: xid={xid}, branchId={branchId}", _xid, BranchId);
                await _xaTransaction.CommitAsync();
            }
        }

        /// <summary>
        /// 回滚XA事务
        /// </summary>
        /// <returns>任务</returns>
        public async Task RollbackAsync()
        {
            if (_xaTransaction != null)
            {
                _logger.LogInformation("回滚XA事务: xid={xid}, branchId={branchId}", _xid, BranchId);
                await _xaTransaction.RollbackAsync();
            }
        }

        /// <summary>
        /// 准备XA事务
        /// </summary>
        /// <returns>任务</returns>
        public async Task PrepareAsync()
        {
            if (_xaTransaction != null)
            {
                _logger.LogInformation("准备XA事务: xid={xid}, branchId={branchId}", _xid, BranchId);
                await _xaTransaction.PrepareAsync();
            }
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        /// <param name="disposing">是否正在释放</param>
        protected override void Dispose(bool disposing)
        {
            if (!_disposed && disposing)
            {
                _innerConnection?.Dispose();
                _xaTransaction?.Dispose();
                _disposed = true;
            }
            
            base.Dispose(disposing);
        }
    }

    /// <summary>
    /// XA事务类，实现XA协议的两阶段提交
    /// </summary>
    public class XaTransaction : DbTransaction, IDisposable
    {
        private readonly DbConnection _connection;
        private readonly string _xid;
        private readonly ILogger<XaTransaction> _logger;
        private DbTransaction _innerTransaction;
        private bool _disposed = false;
        private bool _prepared = false;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="connection">数据库连接</param>
        /// <param name="xid">全局事务ID</param>
        /// <param name="logger">日志记录器</param>
        public XaTransaction(DbConnection connection, string xid, ILogger<XaTransaction>? logger = null)
        {
            _connection = connection ?? throw new ArgumentNullException(nameof(connection));
            _xid = xid ?? throw new ArgumentNullException(nameof(xid));
            _logger = logger ?? Microsoft.Extensions.Logging.Abstractions.NullLogger<XaTransaction>.Instance;
            
            // 开始内部事务
            _innerTransaction = connection.BeginTransaction();
        }

        /// <summary>
        /// 数据库连接
        /// </summary>
        protected override DbConnection DbConnection => _connection;

        /// <summary>
        /// 内部事务
        /// </summary>
        public DbTransaction InnerTransaction => _innerTransaction;

        /// <summary>
        /// 事务隔离级别
        /// </summary>
        public override IsolationLevel IsolationLevel => _innerTransaction.IsolationLevel;

        /// <summary>
        /// 提交事务
        /// </summary>
        public override void Commit()
        {
            // XA协议要求先准备再提交，这里只是标记为准备提交
            // 实际提交由全局事务协调器在第二阶段调用
            _logger.LogInformation("标记XA事务为准备提交: xid={xid}", _xid);
        }

        /// <summary>
        /// 回滚事务
        /// </summary>
        public override void Rollback()
        {
            // XA协议要求先准备再回滚，这里只是标记为准备回滚
            // 实际回滚由全局事务协调器在第二阶段调用
            _logger.LogInformation("标记XA事务为准备回滚: xid={xid}", _xid);
        }

        /// <summary>
        /// 准备XA事务
        /// </summary>
        /// <returns>任务</returns>
        public async Task PrepareAsync()
        {
            if (_prepared)
            {
                _logger.LogWarning("XA事务已经准备: xid={xid}", _xid);
                return;
            }

            _logger.LogInformation("准备XA事务: xid={xid}", _xid);
            
            try
            {
                // 根据数据库类型执行不同的准备逻辑
                await PrepareByDatabaseTypeAsync();
                _prepared = true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "准备XA事务失败: xid={xid}", _xid);
                throw;
            }
        }

        /// <summary>
        /// 提交XA事务
        /// </summary>
        /// <returns>任务</returns>
        public async Task CommitAsync()
        {
            if (!_prepared)
            {
                await PrepareAsync();
            }

            _logger.LogInformation("提交XA事务: xid={xid}", _xid);
            
            try
            {
                // 根据数据库类型执行不同的提交逻辑
                await CommitByDatabaseTypeAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "提交XA事务失败: xid={xid}", _xid);
                throw;
            }
        }

        /// <summary>
        /// 回滚XA事务
        /// </summary>
        /// <returns>任务</returns>
        public async Task RollbackAsync()
        {
            _logger.LogInformation("回滚XA事务: xid={xid}", _xid);
            
            try
            {
                // 根据数据库类型执行不同的回滚逻辑
                await RollbackByDatabaseTypeAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "回滚XA事务失败: xid={xid}", _xid);
                throw;
            }
        }

        /// <summary>
        /// 根据数据库类型准备事务
        /// </summary>
        /// <returns>任务</returns>
        private async Task PrepareByDatabaseTypeAsync()
        {
            // 这里简化实现，实际应该根据不同数据库类型执行不同的XA命令
            // 例如：SQL Server使用"PREPARE TRAN"，MySQL使用"XA PREPARE"
            
            // 使用SQL模拟XA准备
            using var command = _connection.CreateCommand();
            command.Transaction = _innerTransaction;
            
            // 获取数据库类型
            var databaseType = _connection.GetType().Name;
            
            switch (databaseType)
            {
                case "SqlConnection":
                    // SQL Server XA准备
                    command.CommandText = $"-- XA PREPARE for {_xid}";
                    await command.ExecuteNonQueryAsync();
                    break;
                    
                case "MySqlConnection":
                    // MySQL XA准备
                    command.CommandText = $"XA PREPARE '{_xid}'";
                    await command.ExecuteNonQueryAsync();
                    break;
                    
                case "NpgsqlConnection":
                    // PostgreSQL XA准备
                    command.CommandText = $"-- XA PREPARE for {_xid}";
                    await command.ExecuteNonQueryAsync();
                    break;
                    
                default:
                    // 默认处理
                    command.CommandText = $"-- XA PREPARE for {_xid}";
                    await command.ExecuteNonQueryAsync();
                    break;
            }
        }

        /// <summary>
        /// 根据数据库类型提交事务
        /// </summary>
        /// <returns>任务</returns>
        private async Task CommitByDatabaseTypeAsync()
        {
            // 这里简化实现，实际应该根据不同数据库类型执行不同的XA命令
            // 例如：SQL Server使用"COMMIT TRAN"，MySQL使用"XA COMMIT"
            
            // 使用SQL模拟XA提交
            using var command = _connection.CreateCommand();
            command.Transaction = _innerTransaction;
            
            // 获取数据库类型
            var databaseType = _connection.GetType().Name;
            
            switch (databaseType)
            {
                case "SqlConnection":
                    // SQL Server XA提交
                    command.CommandText = $"-- XA COMMIT for {_xid}";
                    await command.ExecuteNonQueryAsync();
                    _innerTransaction.Commit();
                    break;
                    
                case "MySqlConnection":
                    // MySQL XA提交
                    command.CommandText = $"XA COMMIT '{_xid}'";
                    await command.ExecuteNonQueryAsync();
                    _innerTransaction.Commit();
                    break;
                    
                case "NpgsqlConnection":
                    // PostgreSQL XA提交
                    command.CommandText = $"-- XA COMMIT for {_xid}";
                    await command.ExecuteNonQueryAsync();
                    _innerTransaction.Commit();
                    break;
                    
                default:
                    // 默认处理
                    command.CommandText = $"-- XA COMMIT for {_xid}";
                    await command.ExecuteNonQueryAsync();
                    _innerTransaction.Commit();
                    break;
            }
        }

        /// <summary>
        /// 根据数据库类型回滚事务
        /// </summary>
        /// <returns>任务</returns>
        private async Task RollbackByDatabaseTypeAsync()
        {
            // 这里简化实现，实际应该根据不同数据库类型执行不同的XA命令
            // 例如：SQL Server使用"ROLLBACK TRAN"，MySQL使用"XA ROLLBACK"
            
            // 使用SQL模拟XA回滚
            using var command = _connection.CreateCommand();
            command.Transaction = _innerTransaction;
            
            // 获取数据库类型
            var databaseType = _connection.GetType().Name;
            
            switch (databaseType)
            {
                case "SqlConnection":
                    // SQL Server XA回滚
                    command.CommandText = $"-- XA ROLLBACK for {_xid}";
                    await command.ExecuteNonQueryAsync();
                    _innerTransaction.Rollback();
                    break;
                    
                case "MySqlConnection":
                    // MySQL XA回滚
                    command.CommandText = $"XA ROLLBACK '{_xid}'";
                    await command.ExecuteNonQueryAsync();
                    _innerTransaction.Rollback();
                    break;
                    
                case "NpgsqlConnection":
                    // PostgreSQL XA回滚
                    command.CommandText = $"-- XA ROLLBACK for {_xid}";
                    await command.ExecuteNonQueryAsync();
                    _innerTransaction.Rollback();
                    break;
                    
                default:
                    // 默认处理
                    command.CommandText = $"-- XA ROLLBACK for {_xid}";
                    await command.ExecuteNonQueryAsync();
                    _innerTransaction.Rollback();
                    break;
            }
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        /// <param name="disposing">是否正在释放</param>
        protected override void Dispose(bool disposing)
        {
            if (!_disposed && disposing)
            {
                _innerTransaction?.Dispose();
                _disposed = true;
            }
            
            base.Dispose(disposing);
        }
    }
}